[READ-ONLY] a fast, modern browser for the npm registry
at main 68 lines 1.5 kB view raw
1import { CACHE_MAX_AGE_ONE_DAY } from '#shared/utils/constants' 2 3type GitHubContributorWeek = { 4 w: number 5 a: number 6 d: number 7 c: number 8} 9 10type GitHubContributorStats = { 11 total: number 12 weeks: GitHubContributorWeek[] 13} 14 15export default defineCachedEventHandler( 16 async event => { 17 const owner = getRouterParam(event, 'owner') 18 const repo = getRouterParam(event, 'repo') 19 20 if (!owner || !repo) { 21 throw createError({ 22 status: 400, 23 message: 'repository not provided', 24 }) 25 } 26 27 const url = `https://api.github.com/repos/${owner}/${repo}/stats/contributors` 28 const headers = { 29 'User-Agent': 'npmx', 30 'Accept': 'application/vnd.github+json', 31 } 32 33 const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) 34 const maxAttempts = 6 35 let delayMs = 1000 36 37 try { 38 for (let attempt = 0; attempt < maxAttempts; attempt += 1) { 39 const response = await $fetch.raw<GitHubContributorStats[]>(url, { headers }) 40 const status = response.status 41 42 if (status === 200) { 43 return Array.isArray(response._data) ? response._data : [] 44 } 45 46 if (status === 204) { 47 return [] 48 } 49 50 if (status === 202) { 51 if (attempt === maxAttempts - 1) return [] 52 await sleep(delayMs) 53 delayMs = Math.min(delayMs * 2, 16_000) 54 continue 55 } 56 57 return [] 58 } 59 60 return [] 61 } catch { 62 return [] 63 } 64 }, 65 { 66 maxAge: CACHE_MAX_AGE_ONE_DAY, 67 }, 68)